package org.dyndns.opendemogroup.optimizer.operations;

import java.util.HashSet;

import org.dyndns.opendemogroup.optimizer.Member;

/**
 * Based on the description in Page 2 of the assignment handout, but with an
 * additional order-preserving addition.
 */
public class OrderedPartiallyMappedCrossover extends
		OrderPreservingOperationBase
{

	@Override
	void perform ( Member parentOne, Member parentTwo, Member child, int a,
			int b )
	{
		final int length = parentOne.genome.length;
		HashSet<Double> taken = new HashSet<Double> ( );
		HashSet<Double> usedSlot = new HashSet<Double> ( );

		// { copy the items between A and B from parent 1 into the child
		for ( int i = a; i < b; i++ )
		{
			final double allele = parentOne.genome[i];
			child.genome[i] = allele;
			taken.add ( allele );
			usedSlot.add ( (double) i );
		}
		// }

		// { for parts of the child's array outside the range [A,B],
		// copy only those items from parent 2, which haven't already been
		// taken from parent 1.
		for ( int i = 0; i < a; i++ )
		{
			final double allele = parentTwo.genome[i];
			if ( !taken.contains ( allele ) )
			{
				child.genome[i] = allele;
				taken.add ( allele );
				usedSlot.add ( (double) i );
			}
		}
		for ( int i = b; i < length; i++ )
		{
			final double allele = parentTwo.genome[i];
			if ( !taken.contains ( allele ) )
			{
				child.genome[i] = allele;
				taken.add ( allele );
				usedSlot.add ( (double) i );
			}
		}
		// }

		// { to fill in the gaps, use the items that have not yet been taken
		for ( int i = 0, j = 0; i < length; i++ )
		{
			// if slot "i" hasn't been used yet
			if ( !usedSlot.contains ( (double) i ) )
			{
				while ( taken.contains ( parentOne.genome[j] ) )
				{
					j++;
				}
				final double allele = parentOne.genome[j];
				child.genome[i] = allele;
				taken.add ( (double) allele );
			}
		}
		// }
	}
}
